#include <limits.h>

#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/Foundation.h>
#import <UIKit/UIHardware.h>
#import <UIKit/UIWindow.h>
#import <UIKit/UITransitionView.h>

#import "Application.h"
#import "PreferencesView.h"
#import "MouseView.h"
#import "WinRemoconProtocol.h"

@implementation Application

+ (void)initialize
{
	NSMutableDictionary *defaultValues = [NSMutableDictionary dictionary];
	[defaultValues setValue: [NSNumber numberWithInt: 7378] forKey: @"host_port"];
	[defaultValues setValue: @"192.168.0.2" forKey: @"host_ip_address"];
	[defaultValues setValue: [NSNumber numberWithInt: 5] forKey: @"margin"];
	[defaultValues setValue: [NSNumber numberWithBool: NO] forKey: @"move_absolute"];
	[defaultValues setValue: [NSNumber numberWithBool: NO] forKey: @"gravity"];
	[[NSUserDefaults standardUserDefaults] registerDefaults: defaultValues];
}

- (void)applicationDidFinishLaunching: (id)unused
{
	// screen rect
	CGRect frame = [UIHardware fullScreenApplicationContentRect];
	frame.origin = CGPointZero;
	
	// transition view
	mainView = [[UITransitionView alloc] initWithFrame: frame];
	
	// view
	view = [[MouseView alloc] initWithFrame: frame];
	[view setMouseDelegate: self];
	
	// create window
	window = [[UIWindow alloc] initWithContentRect: frame];
	[window setContentView: mainView];
	[window orderFront: self];
	[window makeKey: self];
	[window _setHidden: NO];
	
	// preferences view
	prefsView = [[PreferencesView alloc] initWithFrame: frame parent: self];
	
	// main view
	[mainView transition: 0 toView: view];
	
	// socket
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	addr.sin_family = AF_INET;
	
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	
	addr.sin_port = htons([defaults integerForKey: @"host_port"]);
	addr.sin_addr.s_addr = inet_addr([[defaults objectForKey: @"host_ip_address"] cStringUsingEncoding: NSASCIIStringEncoding]);
}

- (void)dealloc
{
	[prefsView release];
	[view release];
	[mainView release];
	[window release];
	[super dealloc];
	
	close(socket);
}

- (void)mouseMoveAbsolute: (CGPoint)p
{
	if (![prefsView moveAbsolute])
		return;
	
	unsigned char data[5];
	unsigned short *dp = (unsigned short *)&data[1];
	*dp++ = htons((unsigned short)p.y);
	*dp = htons((unsigned short)USHRT_MAX - p.x);
	data[0] = MOUSE_MOVE_ABSOLUTE_WORD;
	
	sendto(sock, data, 5, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseMoveRelative: (CGPoint)d
{
	if ([prefsView moveAbsolute])
		return;
	
	unsigned char data[3];
	data[0] = MOUSE_MOVE_RELATIVE;
	data[1] = (signed char)d.y;
	data[2] = (signed char)(- d.x);
	
	sendto(sock, data, 3, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseWheel: (int)rev
{
	unsigned char data[2];
	
	data[0] = MOUSE_WHEEL;
	data[1] = (signed char)rev;
	
	sendto(sock, data, 2, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseLeftButtonClick
{
	unsigned char data[2];
	unsigned char flag = MOUSE_LEFT_BUTTON;
	
	data[0] = MOUSE_BUTTON_CLICK;
	data[1] = flag;
	
	sendto(sock, data, 2, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseRightButtonClick
{
	unsigned char data[2];
	unsigned char flag = MOUSE_RIGHT_BUTTON;
	
	data[0] = MOUSE_BUTTON_CLICK;
	data[1] = flag;
	
	sendto(sock, data, 2, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)statusBarMouseDown: (GSEventRef)event
{
	[mainView transition: 1 toView: prefsView];
}

- (void)navigationBar: (UINavigationBar*)navigationBar buttonClicked: (int)button
{
	addr.sin_port = htons([prefsView hostPort]);
	addr.sin_addr.s_addr = inet_addr([[prefsView hostIPAddress] cStringUsingEncoding: NSASCIIStringEncoding]);
	
	[prefsView save];

	[mainView transition: 2 toView: view];
}

- (void)acceleratedInX: (float)x Y: (float)y  Z: (float)z
{
	if (![prefsView gravity])
		return;
	
	unsigned char data[5];
	unsigned short *dp = (unsigned short *)&data[1];
	*dp++ = htons((unsigned short)((1.0 - x - 0.5) * USHRT_MAX));
	*dp = htons((unsigned short)((1.0 - y - 0.5) * USHRT_MAX));
	data[0] = MOUSE_MOVE_ABSOLUTE_WORD;
	
	sendto(sock, data, 5, 0, (struct sockaddr *)&addr, sizeof(addr));
}

@end
